# support
$from tetragen import *
$tetragen = Tetragen()
$nameList = ['tetragen']

# program
#Prog : StList : a0 = filter(bool, a1) ;
Prog : StList : a0 = a1 ;

# list of Statements
StL : St : a0 = a1 ;
StList : StL : a0 = a1 ;
StList : StList StL : a0 = a1 + a2 ;

# code block
StBlock : LFPAREN StList RFPAREN : a0 = tetragen.closeBlock(a2) ;

# statements
St : VarDecl SEMICOLON : a0 = a1[0] ;
St : VarAssign SEMICOLON : a0 = a1 ;
St : VarDeclAssign SEMICOLON : a0 = a1 ;
St : StBlock : a0 = a1 ;

St : PrintSt SEMICOLON : a0 = a1 ;
St : ReadSt  SEMICOLON : a0 = a1 ;

St : LabelSt SEMICOLON : a0 = a1 ;
St : GotoSt SEMICOLON : a0 = a1 ;

St : IfSt : a0 = a1 ;
St : WhileSt : a0 = a1 ;
St : ForSt : a0 = a1 ;

St : TypeDef SEMICOLON : a0 = a1 ;

St : FuncDef      : a0 = a1 ;
St : OperatorDef  : a0 = a1 ;
St : FuncCallSt SEMICOLON : a0 = a1[0] ;
St : ReturnSt SEMICOLON : a0 = a1 ;

# functions
#FuncStart : ID LPAREN : ;

# ArgDeclList  : VarDecl : a0 = a1 ;
# ArgDeclList  : ArgDeclList COLON VarDecl : a0 = a1 + a3 ;
# FuncDef  : ID ID LPAREN ArgDeclList RPAREN StBlock : a0 = tetragen.funcDef(a1, a2, a4, a6) ;
# FuncDef  : ID ID LPAREN RPAREN StBlock : a0 = tetragen.funcDef(a1, a2, [], a5) ;

# ID0 : ID : a0 = a1 ;

# ArgList : ID0 COLON ID0 :     a0 = [ tetragen.getVar(a1)[1], tetragen.getVar(a1)[3] ] ;
# ArgList : ArgList COLON ID0 : a0 = a1 + [ tetragen.getVar(a3)[1] ] ;
# FuncCall : ID LPAREN ArgList RPAREN : a0 = a2 ;
# FuncCall : ID LPAREN ID0 RPAREN : a0 = a2 ;
# FuncCall : ID LPAREN RPAREN : a0 = a1 ;

ArgDeclList  : VarDecl : a0 = a1[0] ;
ArgDeclList  : ArgDeclList COLON VarDecl : a0 = a1 + a3[0] ;
FuncDefBody  : ID ID LPAREN ArgDeclList RPAREN : a0 = a1, a2, a4 ;
FuncDefBody  : ID ID LPAREN RPAREN : a0 = a1, a2, [] ;
FuncDef  : FuncDefBody StBlock : a0 = tetragen.funcDef(a1[0], a1[1], a1[2], a2) ;

OperatorDefBody : ID operator PLUS  LPAREN ArgDeclList RPAREN : a0 = a1, a3, a5 ;
OperatorDefBody : ID operator MINUS LPAREN ArgDeclList RPAREN : a0 = a1, a3, a5 ;
OperatorDefBody : ID operator DIV   LPAREN ArgDeclList RPAREN : a0 = a1, a3, a5 ;
OperatorDefBody : ID operator MULT  LPAREN ArgDeclList RPAREN : a0 = a1, a3, a5 ;

OperatorDefBody : ID operator NOT   LPAREN ArgDeclList RPAREN : a0 = a1, a3, a5 ;

OperatorDefBody : ID operator NEQU  LPAREN ArgDeclList RPAREN : a0 = a1, a3, a5 ;
OperatorDefBody : ID operator EQUALS LPAREN ArgDeclList RPAREN : a0 = a1, a3, a5 ;

OperatorDefBody : ID operator GEQU  LPAREN ArgDeclList RPAREN : a0 = a1, a3, a5 ;
OperatorDefBody : ID operator LEQU  LPAREN ArgDeclList RPAREN : a0 = a1, a3, a5 ;
OperatorDefBody : ID operator GREAT LPAREN ArgDeclList RPAREN : a0 = a1, a3, a5 ;
OperatorDefBody : ID operator LESS  LPAREN ArgDeclList RPAREN : a0 = a1, a3, a5 ;

OperatorDef     : OperatorDefBody StBlock : a0 = tetragen.operatorDef(a1[0], a1[1], a1[2], a2)

#ArgList : Expr COLON :     a0 = [ tetragen.getVar(a1)[1], tetragen.getVar(a1)[3] ] ;
#ArgList : ArgList Expr COLON : a0 = a1 + [ tetragen.getVar(a3)[1] ] ;
#FuncCall : ID LPAREN ArgList Expr RPAREN : a0 = a2 ;
FuncCallArgs : ID LPAREN Expr : a0 = a1, [a3] ;
FuncCallArgs : FuncCallArgs COLON Expr : a0 = a1[0], a1[1] + [a3] ;
FuncCall : FuncCallArgs RPAREN : a0 = tetragen.funcCall(a1[0], a1[1]) ;
FuncCall : ID LPAREN RPAREN : a0 = tetragen.funcCall(a1, [])  ;

FuncCallSt : FuncCall : a0 = a1 ;

ReturnSt : return Expr : a0 = tetragen.funcReturn(a2) ;

# types
TypeDef : StructDef : a0 = a1 ;

StructDef : struct ID StBlock : a0 = tetragen.defStruct(a2, a3) ;


# variable actions
VarName   : ID             : a0 = a1 ;
Var       : VarName        : a0 = tetragen.getVar(a1);
Var       : Var DOT ID     : a0 = tetragen.getSubVar(a1, a3) ;
Var0      : Var LSPAREN Expr : a0 = tetragen.getSubArray(a1, a3) ;
Var       : Var0 RSPAREN     : a0 = a1 ;

VarDecl   : ID VarName            : a0 = tetragen.addVar(a1, a2) ;
VarDecl0  : VarDecl LSPAREN DIGIT : a0 = tetragen.setArraySize(a1, a3)
VarDecl   : VarDecl0 RSPAREN      : a0 = a1 ;
VarAssign : Var EQASSIGN Expr                : a0 = a1[0] + tetragen.assignValue(a1[1], a3) ;
VarAssign : Var EQASSIGN FuncCall            : a0 = a1[0] + tetragen.assignValue(a1[1], a3) ;
VarDeclAssign : VarDecl EQASSIGN Expr        : a0 = a1[0] + tetragen.assignValue(a1[1], a3) ;
VarDeclAssign : VarDecl EQASSIGN FuncCall    : a0 = a1[0] + tetragen.assignValue(a1[1], a3) ;

# expressions
ExprParen : DOUBLE   : a0 = tetragen.getConst(float(a1), 'float') ;
ExprParen : DIGIT    : a0 = tetragen.getConst(int(a1), 'int') ;
ExprParen : Var      : a0 = a1 ;
ExprParen : LPAREN ExprProxy RPAREN : a0 = a2 ;

ExprMul : ExprParen : a0 = a1 ;
ExprMul : ExprMul MULT ExprParen : a0 = tetragen.operatorCall(a2, a1, a3) ;
ExprMul : ExprMul DIV  ExprParen : a0 = tetragen.operatorCall(a2, a1, a3) ;

ExprSum : ExprMul : a0 = a1 ;
ExprSum : ExprSum PLUS  ExprMul : a0 = tetragen.operatorCall(a2, a1, a3) ;
ExprSum : ExprSum MINUS ExprMul : a0 = tetragen.operatorCall(a2, a1, a3) ;
ExprSum : MINUS ExprMul         : a0 = tetragen.unarOperatorCall(a1, a2) ;

# comparaions
ExprComp : ExprSum : a0 = a1
ExprComp : NOT ExprComp : a0 = tetragen.unarOperatorCall(a1, a2) ;
ExprComp : ExprSum LESS   ExprSum : a0 = tetragen.operatorCall(a2, a1, a3) ;
ExprComp : ExprSum GREAT  ExprSum : a0 = tetragen.operatorCall(a2, a1, a3) ;
ExprComp : ExprSum LEQU   ExprSum : a0 = tetragen.operatorCall(a2, a1, a3) ;
ExprComp : ExprSum GEQU   ExprSum : a0 = tetragen.operatorCall(a2, a1, a3) ;
ExprComp : ExprSum EQUALS ExprSum : a0 = tetragen.operatorCall(a2, a1, a3) ;
ExprComp : ExprSum NEQU   ExprSum : a0 = tetragen.operatorCall(a2, a1, a3) ;

Expr : ExprComp : a0 = a1
ExprProxy : Expr : a0 = a1 # NB!! there MUST NOT be any difference between Expr and ExprProxy (trailing comma in funcall issue)

# IO
PrintSt : print Expr : a0 = tetragen.printValue(a2) ;
ReadSt  : read  Var  : a0 = tetragen.readValue(a2) ;


# conditionals
IfBody : if LPAREN ExprProxy RPAREN : a0 = a3 ;
IfSt    : IfBody  St : a0 = tetragen.ifSt(a1, a2)    ;

WhileBody : while LPAREN ExprProxy RPAREN : a0 = a3 ;
WhileSt : WhileBody St : a0 = tetragen.whileSt(a1, a2) ;

ForAssign : VarAssign : a0 = a1 ;
ForInner0 : ForAssign COLON Expr : a0 = a1, a3 ;
ForInner  : ForInner0  COLON ForAssign RPAREN : a0 = a1[0], a1[1], a3 ;
ForBody   : for LPAREN ForInner : a0 = a3 ;
ForSt     : ForBody St : a0 = tetragen.forSt(*(a1 + (a2,))) ;

LabelSt : label ID : a0 = tetragen.defLabel(a2) ;
GotoSt  : goto  ID : a0 = tetragen.gotoLabel(a2) ;
